package com.xpec.c4.game.utility.wordfilter;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.xpec.c4.game.utility.GameUtility;


/**
 * 从网上copy了一个并且改了bug，并且加了替换成***的功能
 * @author linyue
 *
 * 修正了會丟失最長過濾詞的Bug 2011-09-16
 * @author zhangyuan 
 */
public class WordFilter
{
	private static final Log log = LogFactory.getLog(WordFilter.class);
	
	private Map<Character, FilterTreeNode> head
			= new Hashtable<Character, FilterTreeNode>();

	/**
	 * 
	 * @param filename
	 * @param toLowercase
	 */
	public void loadFromFile(String filename, boolean toLowercase)
	{
		List<String> strs = GetBadWords(filename);
		for (int i = 0; i < strs.size(); i++)
		{
			String str = strs.get(i);
			if(str == null || str.length() < 1){
				continue;
			}
			if(toLowercase)
			{
				addBadWord(str.toLowerCase());
			}
			else {
				addBadWord(str);
			}
		}
	}
	
	/**
	 * 從陣列加過濾字
	 * 
	 * @param wordList
	 */
	public void addFromArrayList(ArrayList<String> wordList) {
		if (GameUtility.getArrayListSize(wordList) == 0) {
			return;
		}

		for (String word : wordList) {
			if (GameUtility.isHaveString(word)) {
				addBadWord(word.toLowerCase());
			}
		}
	}

	public void addBadWord(String str)
	{
		char c = str.charAt(0);
		if (head.containsKey(c))
		{
			FilterTreeNode node = (FilterTreeNode) head.get(c);
			addNode(node, str, 1);
		}
		else
		{
			FilterTreeNode node = new FilterTreeNode();
			node.setText(c);
			if (str.length() == 1)
			{
				node.setLeaf(true);
			}
			else
			{
				node.setLeaf(false);
			}

			head.put(c, node);
			addNode(node, str, 1);
		}
	}

	private void addNode(FilterTreeNode node, String str, int p)
	{
		if (str.length() > p)
		{
			if (node.getChildNodes() == null)
			{
				node.setChildNodes(new Hashtable());
			}

			FilterTreeNode n;
			if (!node.getChildNodes().containsKey(str.charAt(p)))
			{
				n = new FilterTreeNode();
				n.setText(str.charAt(p));
				if (str.length() == p + 1)
				{
					n.setLeaf(true);
				}
				else
				{
					n.setLeaf(false);
				}

				node.getChildNodes().put(str.charAt(p), n);
			}
			else
			{
				n = (FilterTreeNode) node.getChildNodes().get(str.charAt(p));
			}

			addNode(n, str, p + 1);
		}

	}

	public String pass(String str)
	{
		int total;
		while(true)
		{
			total = str.length();
			boolean isStrChange = false;
			for (int current = 0; current < total; current++)
			{
				char lCurrentChar = str.charAt(current);
				if (head.containsKey(lCurrentChar))
				{
					FilterTreeNode node = (FilterTreeNode) head.get(lCurrentChar);
					String lMatching = containChar(node, str, current + 1, total, String.valueOf(node.getText()));
					if (lMatching != null)
					{
						StringBuilder sb = new StringBuilder();
						for (int i = 0; i < lMatching.length(); i++)
						{
							sb.append("*");
						}
						str = str.replace(lMatching, sb);
						isStrChange = true;
						break;
					}
				}
			}
			if (!isStrChange)
			{
				return str;
			}
		}
	}
	
	public String filterSpace(String str)
	{
		String reg = "(?i)(\\s)|(　)";
		return str.replaceAll(reg, "");
	}

	private String containChar(FilterTreeNode node, String str, int p, int total, String pMatchingKeyWord)
	{

		if (node.getLeaf() == true)
		{
			return pMatchingKeyWord;
		}

		if (p >= total)
		{
			return null;
		}

		if (node.getChildNodes().containsKey(str.charAt(p)))
		{
			FilterTreeNode n = (FilterTreeNode) node.getChildNodes().get(str.charAt(p));
			String lNextMatching = containChar(n, str, p + 1, total, pMatchingKeyWord + n.getText());
			if (lNextMatching != null)
			{
				return lNextMatching;
			}
			else
			{
				return null;
			}
		}
		else
		{
			return null;
		}

	}

	private List<String> GetBadWords(String filename)
	{
		try
		{
			int lMaxLength = 0;
			Hashtable<Integer, LinkedList<String>> lLinkedLists = new Hashtable<Integer, LinkedList<String>>();
			List<String> badWords = new ArrayList<String>();
			
			BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(
				filename), "UTF-8"));
			String lLine = reader.readLine();
			while (lLine != null)
			{
				int lLength = lLine.length();
				LinkedList<String> lLinkedList = lLinkedLists.get(lLength);
				if (lLinkedList == null)
				{
					lLinkedList = new LinkedList<String>();
				}
				lLinkedLists.put(lLength, lLinkedList);
				//
				lLinkedList.push(lLine);
				//
				if (lLength > lMaxLength)
				{
					lMaxLength = lLength;
				}
				lLine = reader.readLine();
			}
			for (int i = 0; i <= lMaxLength; i++)
			{
				LinkedList<String> lLinkedList = lLinkedLists.get(i);
				if (lLinkedList != null)
				{
					Iterator<String> lIterator = lLinkedList.iterator();
					while(lIterator.hasNext())
					{
						String lNextString = lIterator.next();
						badWords.add(lNextString);
					}
				}
			}
			reader.close();
			return badWords;
		}
		catch (Exception e)
		{
			if(log.isErrorEnabled()){
				log.error(e, e);
			}
			return null;
		}
	}

}
